#include <boost/test/unit_test.hpp>

#include <phalanx/utility/begin_end.hpp.cu>
using namespace phalanx;

namespace ns_begin_end
{

BOOST_AUTO_TEST_CASE( _begin )
{
    {
        int v[] = { 0xdeadbeaf, 0 };
        BOOST_REQUIRE(( &*begin( v ) == v ));

        BOOST_REQUIRE(( *begin( v ) == 0xdeadbeaf ));
        *begin( v ) = 0xacacacac;
        BOOST_REQUIRE(( *begin( v ) == 0xacacacac ));
    }

    {
        int2 v = { 0xdeadbeaf, 0 };
        BOOST_REQUIRE(( &*begin( v ) == &v.x ));

        BOOST_REQUIRE(( *begin( v ) == 0xdeadbeaf ));
        *begin( v ) = 0xacacacac;
        BOOST_REQUIRE(( *begin( v ) == 0xacacacac ));
    }
}

BOOST_AUTO_TEST_CASE( _end )
{
    {
        int v[] = { 0, 0xdeadbeaf };
        BOOST_REQUIRE(( &*( end( v ) - 1 ) == ( v + 1 ) ));

        BOOST_REQUIRE(( *( end( v ) - 1 ) == 0xdeadbeaf ));
        *( end( v ) - 1 ) = 0xacacacac;
        BOOST_REQUIRE(( *( end( v ) - 1 ) == 0xacacacac ));
    }

    {
        int2 v = { 0, 0xdeadbeaf };
        BOOST_REQUIRE(( &*( end( v ) - 1 ) == ( &v.x + 1 ) ));
        BOOST_REQUIRE(( &*--end( v ) == ( &v.x + 1 ) ));

        BOOST_REQUIRE(( *( end( v ) - 1 ) == 0xdeadbeaf ));
        BOOST_REQUIRE(( *--end( v ) == 0xdeadbeaf ));
        *--end( v ) = 0xacacacac;
        BOOST_REQUIRE(( *( end( v ) - 1 ) == 0xacacacac ));
        BOOST_REQUIRE(( *--end( v ) == 0xacacacac ));
    }
}

BOOST_AUTO_TEST_CASE( _range )
{
    {
        int v[] = { 0xdeadbeaf, 0 };
        BOOST_REQUIRE(( begin( v ) == ( end( v ) - 2 ) ));
        BOOST_REQUIRE(( ( begin( v ) + 1 ) == ( end( v ) - 1 ) ));

        *begin( v ) = 0xacacacac;
        BOOST_REQUIRE(( *( end( v ) - 1 ) == 0 ));
        BOOST_REQUIRE(( *( end( v ) - 2 ) == 0xacacacac ));
    }

    {
        int2 v = { 0xdeadbeaf, 0 };
        BOOST_REQUIRE(( begin( v ) == ( end( v ) - 2 ) ));
        BOOST_REQUIRE(( begin( v ) == ----end( v ) ));
        BOOST_REQUIRE(( ( begin( v ) + 1 ) == ( end( v ) - 1 ) ));
        BOOST_REQUIRE(( ++begin( v ) == --end( v ) ));

        *begin( v ) = 0xacacacac;
        BOOST_REQUIRE(( *( end( v ) - 1 ) == 0 ));
        BOOST_REQUIRE(( *--end( v ) == 0 ));
        BOOST_REQUIRE(( *( end( v ) - 2 ) == 0xacacacac ));
        BOOST_REQUIRE(( *----end( v ) == 0xacacacac ));
    }
}

BOOST_AUTO_TEST_CASE( _rbegin )
{
    {
        int v[] = { 0, 0xdeadbeaf };
        BOOST_REQUIRE(( &*rbegin( v ) == ( v + 1 ) ));

        BOOST_REQUIRE(( *rbegin( v ) == 0xdeadbeaf ));
        *rbegin( v ) = 0xacacacac;
        BOOST_REQUIRE(( *rbegin( v ) == 0xacacacac ));
    }

    {
        int2 v = { 0, 0xdeadbeaf };
        BOOST_REQUIRE(( &*rbegin( v ) == ( &v.x + 1 ) ));

        BOOST_REQUIRE(( *rbegin( v ) == 0xdeadbeaf ));
        *rbegin( v ) = 0xacacacac;
        BOOST_REQUIRE(( *rbegin( v ) == 0xacacacac ));
    }
}

BOOST_AUTO_TEST_CASE( _rend )
{
    {
        int v[] = { 0xdeadbeaf, 0 };
        BOOST_REQUIRE(( &*( rend( v ) - 1 ) == v ));

        BOOST_REQUIRE(( *( rend( v ) - 1 ) == 0xdeadbeaf ));
        *( rend( v ) - 1 ) = 0xacacacac;
        BOOST_REQUIRE(( *( rend( v ) - 1 ) == 0xacacacac ));
    }

    {
        int2 v = { 0xdeadbeaf, 0 };
        BOOST_REQUIRE(( &*( rend( v ) - 1 ) == &v.x ));
        BOOST_REQUIRE(( &*--rend( v ) == &v.x ));

        BOOST_REQUIRE(( *( rend( v ) - 1 ) == 0xdeadbeaf ));
        BOOST_REQUIRE(( *--rend( v ) == 0xdeadbeaf ));
        *--rend( v ) = 0xacacacac;
        BOOST_REQUIRE(( *( rend( v ) - 1 ) == 0xacacacac ));
        BOOST_REQUIRE(( *--rend( v ) == 0xacacacac ));
    }
}

BOOST_AUTO_TEST_CASE( _reverce )
{
    {
        int v[] = { 0xdeadbeaf, 0 };
        BOOST_REQUIRE(( ++rbegin( v ) == ( rend( v ) - 1 ) ));

        *++rbegin( v ) = 0xacacacac;
        BOOST_REQUIRE(( *( rend( v ) - 1 ) == 0xacacacac ));
    }

    {
        int2 v = { 0xdeadbeaf, 0 };
        BOOST_REQUIRE(( ( rbegin( v ) + 1 ) == ( rend( v ) - 1 ) ));
        BOOST_REQUIRE(( ++rbegin( v ) == --rend( v ) ));

        *++rbegin( v ) = 0xacacacac;
        BOOST_REQUIRE(( *( rend( v ) - 1 ) = 0xacacacac ));
        BOOST_REQUIRE(( *--rend( v ) = 0xacacacac ));
    }
}

} // namespace ns_begin_end

